package com.lan;

import com.lan.model.Symbol;
import com.lan.model.Type;
import com.lan.model.symbol.*;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ParseTree;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ScriptContext {

    // AST
    private ParseTree ast;

    private Ns ns;

    // AST节点对应的Symbol
//    private Map<ParserRuleContext, Variable> nodeOfVariable = new HashMap<>();

    // AST节点对应的Scope，如for、函数调用会启动新的Scope
    private Map<ParserRuleContext, Scope> nodeOfScope = new HashMap<>();

    public ParseTree getAst() {
        return ast;
    }

    public void setAst(ParseTree ast) {
        this.ast = ast;
    }

    public Ns getNameSpace() {
        return ns;
    }

    public void setNameSpace(Ns ns) {
        this.ns = ns;
    }

//    public Variable nodeOfVariable(ParserRuleContext ctx) {
//        return nodeOfVariable.get(ctx);
//    }
//
//    public void nodeOfVariable(ParserRuleContext ctx, Variable variable) {
//        nodeOfVariable.put(ctx, variable);
//    }

    public void nodeOfScope(ParserRuleContext ctx, Scope scope) {
        this.nodeOfScope.put(ctx, scope);
    }

    public Scope nodeOfScope(RuleContext ctx) {
        Scope scope = this.nodeOfScope.get(ctx);
        if (scope != null) {
            return scope;
        }
        return this.nodeOfScope(ctx.parent);
    }

    /**
     * 查找某节点所在的Scope
     * 算法：逐级查找父节点，找到一个对应着Scope的上级节点
     *
     * @param node
     * @return
     */
    public Scope scopeOfNode(ParserRuleContext node) {
        Scope rtn = null;
        ParserRuleContext parent = node.getParent();
        if (parent != null) {
            rtn = nodeOfScope.get(parent);
            if (rtn == null) {
                rtn = scopeOfNode(parent);
            }
        }
        return rtn;
    }


    /**
     * 输出本Scope中的内容，包括每个变量的名称、类型。
     *
     * @return 树状显示的字符串
     */
    public String getScopeTreeString() {
        StringBuffer sb = new StringBuffer();
        scopeToString(sb, ns, "");
        return sb.toString();
    }

    private void scopeToString(StringBuffer sb, Scope scope, String indent) {
        sb.append(indent).append(scope).append('\n');
        for (Symbol symbol : scope.getSymbols()) {
            if (symbol instanceof Scope) {
                scopeToString(sb, (Scope) symbol, indent + "\t");
            } else {
                sb.append(indent).append("\t").append(symbol).append('\n');
            }
        }
    }


    /**
     * 通过方法的名称和方法签名查找Function。逐级Scope查找。
     *
     * @param scope
     * @param idName
     * @return
     */
    public Function lookupFunction(Scope scope, String idName) {
        Function rtn = scope.getFunction(idName);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupFunction(scope.getScope(), idName);
        }
        return rtn;
    }


    /**
     * 通过名称查找Variable。逐级Scope查找。
     *
     * @param scope
     * @param idName
     * @return
     */
    public Variable lookupVariable(Scope scope, String idName) {
        Variable rtn = scope.getVariable(idName);
        if (rtn == null && scope.getScope() != null) {
            rtn = lookupVariable(scope.getScope(), idName);
        }
        return rtn;
    }


    public Json lookupJson(Scope scope, String idName) {
        Json rtn = scope.getJson(idName);
        if (rtn == null && scope.getScope() != null) {
            return lookupJson(scope.getScope(), idName);
        }
        return rtn;
    }

    public Jarray lookupJarray(Scope scope, String idName) {
        Jarray rtn = scope.getJarray(idName);
        if (rtn == null && scope.getScope() != null) {
            return lookupJarray(scope.getScope(), idName);
        }
        return null;
    }


    public Ns getNs() {
        return ns;
    }

    public void setNs(Ns ns) {
        this.ns = ns;
    }
}
